import Bullet from "./Bullet";
import { ItemData, 头盔, 突击步枪, 防弹衣 } from "./Datas/Data";
import DroppedItem from "./DroppedItem";
import EnemyController from "./EnemyController";
import { Constant, ItemType } from "./Framework/Const/Constant";
import AudioManager from "./Framework/Managers/AudioManager";
import { BundleManager, Bundles } from "./Framework/Managers/BundleManager";
import { DataManager } from "./Framework/Managers/DataManager";
import { EventManager, MyEvent } from "./Framework/Managers/EventManager";
import { PoolManager } from "./Framework/Managers/PoolManager";
import { UIManager } from "./Framework/Managers/UIManager";
import NodeUtil from "./Framework/Utils/NodeUtil";
import { ResourceUtil } from "./Framework/Utils/ResourceUtil";
import { ZTool } from "./Framework/Utils/ZTool";
import GameManager, { GameMode } from "./GameManager";
import Supplies from "./Supplies";
import GamePanel from "./UI/GamePanel";
import HPBar from "./UI/HPBar";

const { ccclass, property } = cc._decorator;

export enum AniState {
    Idle = "Idle",
    Move = "Move",
    Hit = "Hit",
    Die = "Die"
}

@ccclass
export default class PlayerController extends cc.Component {
    static MAXHP = 300;
    static oriPosition: cc.Vec2 = cc.v2();

    rigidbody: cc.RigidBody = null;
    collider: cc.PhysicsCircleCollider = null;

    animation: cc.Animation = null;
    fireAni: cc.Animation = null;

    Cat: cc.Node;
    FirePos: cc.Node;
    Gun: cc.Node;
    GunSp: cc.Sprite;
    HPBar: cc.Node;

    Equip: cc.Node;
    Equip_Helmet: cc.Sprite;
    Equip_Bulletproof: cc.Sprite;

    AimLine: cc.Node;

    GunAnimation: cc.Animation = null;

    x: number = 0;
    y: number = 0;

    isFire: boolean = false;
    needFire: boolean = false;
    isCooldown: boolean = true;//射击冷却
    isReload: boolean = false;//换弹
    cooldownTimer: number = 0;
    maxSpeed: number = 1000;
    speed: number = 1000;

    state: AniState = AniState.Idle;

    gun = null;

    fireDir: cc.Vec2 = cc.v2();
    hpBar: HPBar = null;

    private _hp = 0;
    public get HP(): number {
        return this._hp;
    }
    public set HP(value: number) {
        // console.error(`血量：${value}`);
        if (value <= 0) {
            value = 0;

            if (GameManager.GameMode == GameMode.TEAM) {
                GamePanel.Instance.RefreshTeamScore(0, 1);
                GameManager.Instance.InitPlayer();
            } else {
                DataManager.PlayerData.Clear();
                EventManager.Scene.emit(MyEvent.RefreshEquip);
                this.StopFire();
                this.StopMove();
                this.PlayAni(AniState.Die);
                GameManager.IsGameOver = true;
                this.scheduleOnce(() => {
                    UIManager.Instance.ShowPanel(Constant.Panel.FailPanel, [this.hitBullet]);
                }, 2);
            }
        }
        this._hp = ZTool.Clamp(value, 0, PlayerController.MAXHP);

        this.hpBar?.Set(value / PlayerController.MAXHP);
    }

    onLoad() {
        this.rigidbody = this.node.getComponent(cc.RigidBody);
        this.collider = this.node.getComponent(cc.PhysicsCircleCollider);
        this.rigidbody.syncPosition(true);
        this.Gun = this.node.getChildByName("Gun");
        this.GunSp = NodeUtil.GetComponent("GunSp", this.node, cc.Sprite);
        this.FirePos = NodeUtil.GetNode("FirePos", this.node);
        this.Cat = NodeUtil.GetNode("Cat", this.node);
        this.animation = NodeUtil.GetComponent("Cat", this.node, cc.Animation);
        this.Equip = NodeUtil.GetNode("Equip", this.node);
        this.Equip_Helmet = NodeUtil.GetComponent("Equip_Helmet", this.node, cc.Sprite);
        this.Equip_Bulletproof = NodeUtil.GetComponent("Equip_Bulletproof", this.node, cc.Sprite);
        this.AimLine = NodeUtil.GetNode("AimLine", this.node);
        this.HPBar = NodeUtil.GetNode("HPBar", this.node);
        this.GunAnimation = this.GunSp.getComponent(cc.Animation);
        this.hpBar = this.HPBar.getComponent(HPBar);

        this.fireAni = this.FirePos.getComponent(cc.Animation);

        this.GunAnimation.on('finished', () => {
            if (this.gun) {
                if (ItemData.IsMeleeWeapon(this.gun.Type)) return;
                let addCount = this.gun.MaxMagazineBulletCount - this.gun.MagazineBulletCount;
                this.gun.MagazineBulletCount += (addCount > this.gun.BulletCount ? this.gun.BulletCount : addCount);
                this.gun.BulletCount -= (addCount > this.gun.BulletCount ? this.gun.BulletCount : addCount);
                EventManager.Scene.emit(MyEvent.RefreshBulletCount);
            }

            this.isReload = false;

            if (this.needFire) {
                this.Fire();
            }
        }, this);

        // PoolManager.GetNode("Prefabs/UI/HPBar", this.node).then(node => {
        //     node.setPosition(0, this.node.getContentSize().height / 2 + 20);
        //     this.hpBar = node.getComponent(HPBar);
        //     this.hpBar.Init();
        //     this.HP = PlayerController.MAXHP;
        // });

        this.hpBar.Init();
        this.HP = PlayerController.MAXHP;

        PlayerController.oriPosition.set(NodeUtil.GetWorldPosition(this.node));
    }

    start() {
        this.RefreshEquip();
    }

    RefreshEquip() {
        this.gun = null;
        this.GunSp.spriteFrame = null;

        this.Equip_Helmet.node.active = DataManager.PlayerData.Helmet != null;
        if (DataManager.PlayerData.Helmet != null) {
            BundleManager.LoadSpriteFrame(Bundles.Item, `${DataManager.PlayerData.Helmet.Type}_${DataManager.PlayerData.Helmet.Name}`).then((sf: cc.SpriteFrame) => {
                this.Equip_Helmet.spriteFrame = sf;
                let position = cc.v2((DataManager.PlayerData.Helmet as 头盔).Position.x, (DataManager.PlayerData.Helmet as 头盔).Position.y);
                this.Equip_Helmet.node.setPosition(position.multiplyScalar(0.4));
            });
        }

        this.Equip_Bulletproof.node.active = DataManager.PlayerData.Bulletproof != null;
        if (DataManager.PlayerData.Bulletproof != null) {
            BundleManager.LoadSpriteFrame(Bundles.Item, `${DataManager.PlayerData.Bulletproof.Type}_${DataManager.PlayerData.Bulletproof.Name}`).then((sf: cc.SpriteFrame) => {
                this.Equip_Bulletproof.spriteFrame = sf;
                let position = cc.v2((DataManager.PlayerData.Bulletproof as 防弹衣).Position.x, (DataManager.PlayerData.Bulletproof as 防弹衣).Position.y);
                this.Equip_Bulletproof.node.setPosition(position.multiplyScalar(0.4));
            });
        }

        // for (let i = 0; i < this.Equip_Helmet.node.children.length; i++) {
        //     const e = this.Equip_Helmet.node.children[i];

        //     console.error(` "Name": "${e.name.split(`_`)[1]}","Type": "头盔", "Price": 2133,  "Position": "${e.getPosition().x},${e.getPosition().y}",  "Lv": 3`);
        // }

        // for (let i = 0; i < this.GunSp.node.children.length; i++) {
        //     const e = this.GunSp.node.children[i];
        //     let type = e.name.split(`_`)[0];
        //     let name = e.name.split(`_`)[1];

        //     let data = DataManager.GetItemData(ItemType[type], name) as any;
        //     console.error(` "Name": "${name}","Type": "${type}", "Price": ${data.Price}, "Damage": ${data.Damage}, "FireRate": ${data.FireRate},  "Desc": "${data.Desc}", "FirePosition": "${e.children[0].getPosition().x},${e.children[0].getPosition().y}"`);
        // }

        let data = null;
        if (DataManager.PlayerData.Weapon_0 != null) {
            data = DataManager.PlayerData.Weapon_0;
        } else if (DataManager.PlayerData.Weapon_1 != null) {
            DataManager.PlayerData.Weapon_1;
        } else if (DataManager.PlayerData.Pistol != null) {
            DataManager.PlayerData.Pistol;
        } else if (DataManager.PlayerData.MeleeWeapon != null) {
            DataManager.PlayerData.MeleeWeapon;
        }


        this.LoadGun(data);
    }

    LoadGun(data) {
        this.AimLine.active = data && ItemData.IsSniper(ItemType[`${data.Type}`]);

        if (data) {
            BundleManager.LoadSpriteFrame(Bundles.Item, `${data.Type}_${data.Name}`).then((sf: cc.SpriteFrame) => {
                this.GunSp.spriteFrame = sf;
            });

            if (data.Type == ItemType[ItemType.近战武器]) {
                this.GunSp.node.setScale(1);
            } else {
                this.GunSp.node.setScale(data.Type == ItemType[ItemType.手枪] ? 0.4 : 1);
                this.FirePos.setPosition(data.FirePosition);
            }

            this.gun = data;
        }
    }

    SetDir(x: number, y: number, rate: number) {
        if (GameManager.IsGameOver) return;

        this.x = x;
        this.y = y;

        if (!this.isFire) {
            this.Cat.scaleX = this.x < 0 ? -1 : 1;

            if ((this.x < 0 ? -1 : 1) != this.Gun.scaleX) {
                this.Gun.scaleX = this.x < 0 ? -1 : 1;
                this.Gun.angle = -this.Gun.angle;
            }
        }

        this.speed = this.maxSpeed;
        this.PlayAni(AniState.Move);
    }

    SetGunDir(dir: cc.Vec2) {
        if (GameManager.IsGameOver) return;

        this.fireDir.set(dir);

        if (this.isFire) {
            this.Cat.scaleX = dir.x < 0 ? -1 : 1;
        }

        let angleRadians = Math.atan2(dir.y, dir.x);
        let angleDegrees = cc.misc.radiansToDegrees(angleRadians);

        this.Gun.scaleX = (angleDegrees > 90 && angleDegrees <= 180 || angleDegrees < -90 && angleDegrees >= -180) ? -1 : 1;
        this.Gun.angle = (angleDegrees > 90 && angleDegrees <= 180 || angleDegrees < -90 && angleDegrees >= -180) ? angleDegrees - 180 : angleDegrees;
    }

    StopMove() {
        this.x = 0;
        this.y = 0;
        if (this.rigidbody.enabled) {
            this.rigidbody.linearVelocity = cc.v2(this.x, this.y);
        }
        this.PlayAni(AniState.Idle);
    }

    PlayAni(state: AniState) {
        if (GameManager.IsGameOver) return;
        if (this.state == state) return;
        this.animation.play(state);
        this.state = state;
    }

    update(dt) {
        if (GameManager.IsGameOver) return;
        if (this.gun) {
            if (!this.isCooldown) {
                this.cooldownTimer += dt;
                if (this.cooldownTimer >= this.gun.FireRate) {
                    this.isCooldown = true;
                    this.cooldownTimer = 0;
                }
            }
        }

        if (this.rigidbody.enabled) {
            this.rigidbody.linearVelocity = cc.v2(this.x * this.speed, this.y * this.speed);
        }
    }

    hitBullet: Bullet = null;

    TakeDamage(bullet: Bullet) {
        this.hitBullet = bullet;

        let damage = bullet.weapon.Damage;
        if (GameManager.IsGameOver) return;

        let data, lv = 0;
        if (DataManager.PlayerData.Bulletproof != null) {
            data = DataManager.PlayerData.Bulletproof;
            lv += data.Lv;
            data.Durability -= damage / 50;
            if (data.Durability <= 0) {
                DataManager.PlayerData.Bulletproof = null;
                EventManager.Scene.emit(MyEvent.RefreshEquip);
            }
        }

        if (DataManager.PlayerData.Helmet != null) {
            data = DataManager.PlayerData.Helmet;
            lv += data.Lv;
            data.Durability -= damage / 50;
            if (data.Durability <= 0) {
                DataManager.PlayerData.Helmet = null;
                EventManager.Scene.emit(MyEvent.RefreshEquip);
            }
        }

        this.HP -= lv == 0 ? damage : damage / lv;
    }

    Reload() {
        if (this.gun) {
            if (this.gun.MagazineBulletCount <= 0 && this.gun.BulletCount <= 0) {
                UIManager.ShowTip("弹匣没有子弹");
                return;
            }

            let clip = this.GunAnimation.getClips().find(e => e.name == this.gun.Name);
            if (clip) {
                this.isReload = true;
                this.GunAnimation.play(clip.name);

                this.isFire = false;
                if (this.gun && (this.gun.Type == ItemType[ItemType.栓动步枪] || this.gun.Type == ItemType[ItemType.射手步枪] || this.gun.Type == ItemType[ItemType.卡宾枪])) {
                    EventManager.Scene.emit(MyEvent.CameraZoomIn);
                }

                this.unschedule(this.StartFire);
            }
        }
    }

    Fire() {
        if (GameManager.IsGameOver) return;
        this.isFire = true;
        this.needFire = true;

        if (!this.gun) return;
        if (this.isReload) return;

        if (this.gun.MagazineBulletCount <= 0 && this.gun.BulletCount <= 0) {
            UIManager.ShowTip("弹匣没有子弹");
            return;
        }

        if (ItemData.IsSniper(ItemType[`${this.gun.Type}`])) {
            let ratio = (this.gun.Type == ItemType[ItemType.栓动步枪] || this.gun.Type == ItemType[ItemType.射手步枪]) ? 0.5 : 0.8;
            EventManager.Scene.emit(MyEvent.CameraZoomOut, ratio);
            if (this.gun.Type == ItemType[ItemType.栓动步枪]) {
                return;
            }
        }

        if (this.gun.MagazineBulletCount <= 0) {
            return;
        }

        if (this.isCooldown && !ItemData.IsSniper(ItemType[`${this.gun.Type}`])) {
            this.isCooldown = false;
            this.StartFire();
        }

        this.schedule(this.StartFire, this.gun.FireRate);
    }

    results = null;
    MeleeAttack() {
        let startPosition = NodeUtil.GetWorldPosition(this.node);
        let endPosition = startPosition.add(this.fireDir.normalize().multiplyScalar(180));
        this.results = cc.director.getPhysicsManager().rayCast(startPosition, endPosition, cc.RayCastType.Closest);
        if (this.results && this.results.length >= 1 && this.results[0].collider.node.group == Constant.Group.Enemy) {
            this.results[0].collider.node.getComponent(EnemyController).TakeMeleeDamage(this.gun.Damage);
        }
    }

    StartFire() {
        if (GameManager.IsGameOver) return;

        if (!this.gun) return;

        if (ItemData.IsMeleeWeapon(this.gun.Type)) {
            let clip = this.GunAnimation.getClips().find(e => e.name == "M9军刀");
            if (clip) {
                this.GunAnimation.play(clip.name);
            }
            this.MeleeAttack();
            return;
        }

        if (this.gun.MagazineBulletCount <= 0) {
            if (this.gun.BulletCount > 0) this.Reload();
            return;
        }

        this.fireAni.play();

        let bulletCount = this.gun.Type == ItemType[ItemType.霰弹枪] ? 5 : 1;

        AudioManager.PlayOneShot(Constant.Audio.Fire);
        this.gun.MagazineBulletCount -= 1;
        EventManager.Scene.emit(MyEvent.RefreshBulletCount);

        for (let i = 0; i < bulletCount; i++) {
            PoolManager.GetNode("Prefabs/Bullet", this.node).then(node => {
                NodeUtil.SetWorldPosition(node, NodeUtil.GetWorldPosition(this.FirePos));
                let recoil = ZTool.GetRandom(this.gun.Recoil * -10 * bulletCount, this.gun.Recoil * 10 * bulletCount);
                node.angle = this.Gun.scaleX < 0 ? this.Gun.angle + recoil - 180 : this.Gun.angle + recoil;
                node.getComponent(Bullet).Init(this.node, this.gun, DataManager.PlayerData);
            });
        }

        PoolManager.GetNode("Prefabs/BulletBlank", this.node).then(node => {
            NodeUtil.SetWorldPosition(node, NodeUtil.GetWorldPosition(this.FirePos));
            node.getComponent(Bullet).InitBlank(this.node, cc.v2(-5 * this.Gun.scaleX, ZTool.GetRandom(5, 8)).multiplyScalar(5), NodeUtil.GetWorldPosition(node).add(cc.v2(ZTool.GetRandom(0.1, 0.5), ZTool.GetRandom(0.1, 0.5))));
        });
    }

    StopFire() {
        this.isFire = false;
        this.needFire = false;

        if (this.gun && (this.gun.Type == ItemType[ItemType.栓动步枪] || this.gun.Type == ItemType[ItemType.射手步枪] || this.gun.Type == ItemType[ItemType.卡宾枪])) {
            EventManager.Scene.emit(MyEvent.CameraZoomIn);
        }

        this.unschedule(this.StartFire);

        if (this.gun && this.gun.Type == ItemType[ItemType.栓动步枪] && this.isCooldown) {
            this.StartFire();
            this.isCooldown = false;
        }

        // PoolManager.GetNode("Prefabs/Grenade", this.node).then(node => {
        //     node.getComponent(Grenade).Throw(this.fireDir);
        // });
    }

    onBeginContact(contact, selfCollider, otherCollider: cc.Collider) {
        if (otherCollider.node.group == "Supplies") {
            let supplies = otherCollider.node.getComponent(Supplies);
            EventManager.Scene.emit(MyEvent.ShowTakeSupplies, true, supplies);
        }

        if (otherCollider.node.group == "DroppedItem") {
            EventManager.Scene.emit(MyEvent.ShowTakeItem, true, otherCollider.node.getComponent(DroppedItem));
        }

        if (otherCollider.node.group == "Bullet") {
            let bullet = otherCollider.node.getComponent(Bullet);
            if (bullet && bullet.weapon) {
                this.TakeDamage(bullet);
            }
            PoolManager.PutNode(otherCollider.node);
        }

        if (otherCollider.node.group == "Evacuation") {
            EventManager.Scene.emit(MyEvent.Evacuation, true);
        }
    }

    onEndContact(contact, selfCollider, otherCollider) {
        if (otherCollider.node.group == "Supplies") {
            EventManager.Scene.emit(MyEvent.ShowTakeSupplies, false);
        }
        if (otherCollider.node.group == "DroppedItem") {
            EventManager.Scene.emit(MyEvent.ShowTakeItem, false);
        }
        if (otherCollider.node.group == "Evacuation") {
            EventManager.Scene.emit(MyEvent.Evacuation, false);
        }
    }

    protected onEnable(): void {
        EventManager.Scene.on(MyEvent.MOVEMENT, this.SetDir, this);
        EventManager.Scene.on(MyEvent.MOVEMENT_STOP, this.StopMove, this);
        EventManager.Scene.on(MyEvent.SET_ATTACK_DIR, this.SetGunDir, this);
        EventManager.Scene.on(MyEvent.Fire, this.Fire, this);
        EventManager.Scene.on(MyEvent.Stop_Fire, this.StopFire, this);
        EventManager.Scene.on(MyEvent.RefreshEquip, this.RefreshEquip, this);
    }

    protected onDisable(): void {
        EventManager.Scene.off(MyEvent.MOVEMENT, this.SetDir, this);
        EventManager.Scene.off(MyEvent.MOVEMENT_STOP, this.StopMove, this);
        EventManager.Scene.off(MyEvent.SET_ATTACK_DIR, this.SetGunDir, this);
        EventManager.Scene.off(MyEvent.Fire, this.Fire, this);
        EventManager.Scene.off(MyEvent.Stop_Fire, this.StopFire, this);
        EventManager.Scene.off(MyEvent.RefreshEquip, this.RefreshEquip, this);
    }
}